package com.wjw.java.games.tankgame4;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import java.util.Vector;

/**
 * 我的画板：游戏的绘图区
 * 为了监听键盘事件,需要实现KeyListener接口,并重写方法
 * 为了让MyPanel不停的重绘子弹,需要让MyPanel实现Runnable接口,当做线程使用
 */
public class MyPanel extends JPanel implements KeyListener,Runnable{
    //自己的坦克
    HeroTank myTank = null;

    //敌人的坦克,这里需要用Vector,线程安全的
    Vector<EnemyTank> enemyTanks = new Vector<>();
    //敌人数量
    int enemyTankSize = 5;

    //存放炸弹,当子弹击中坦克时,就加入一个Bomb对象到bombs集合中
    Vector<Bomb> bombs = new Vector<>();
    //定义三张炸弹图片,用于显示炸弹效果
    File file1 = new File("C:\\Users\\wjw\\Desktop\\basic\\src\\main\\resources\\images\\games\\1.jpeg");
    File file2 = new File("C:\\Users\\wjw\\Desktop\\basic\\src\\main\\resources\\images\\games\\2.jpeg");
    File file3 = new File("C:\\Users\\wjw\\Desktop\\basic\\src\\main\\resources\\images\\games\\3.jpeg");
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;

    /**
     * 1.初始化画板,然后画自己的坦克和敌人的坦克
     */
    public MyPanel(){
        System.out.println("初始化MyPanel画板...");
        //自己的坦克
        myTank = new HeroTank(500,500);
        myTank.setSpeed(10);//设置tank移动的速度

        //敌人的坦克
        for (int i = 0; i < enemyTankSize; i++) {
            //敌人坦克初始坐标
            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
            //设置炮筒向下
            enemyTank.setDirection(2);
            //启动敌人坦克线程,让它随机方向移动
            new Thread(enemyTank).start();
            //给敌人坦克加入一颗子弹
            Shot shot = new Shot(enemyTank.getX()+20,enemyTank.getY()+60,enemyTank.getDirection());
            //加入到射击线程集合
            enemyTank.getShots().add(shot);
            //启动
            new Thread(shot).start();
            //敌人坦克加入到Vector集合中
            enemyTanks.add(enemyTank);
        }

        //三张炸弹图片
        try {
            image1 = ImageIO.read(file1);
            image2 = ImageIO.read(file2);
            image3 = ImageIO.read(file3);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 2.绘图方法,什么时候被调用：
     * 当组件第一次在屏幕上显示时
     * 窗口最大、最小化时
     * 窗口大小发生变化时
     * repaint函数被调用时(刷新组件外观的函数)
     * @param g
     */
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        //填充矩形：游戏背景
        g.fillRect(0,0,1000,750);

        //画自己的坦克
        if(myTank != null && myTank.isLive() == true){
            drawTank(myTank.getX(),myTank.getY(),g,myTank.getDirection(),1);
        }
        //画自己坦克的子弹线路,单发子弹
        /*if(myTank.getShot() != null && myTank.getShot().isLive() == true){
            //主要改变子弹的x,y坐标,绘制子弹的移到轨迹靠run(),没100毫秒重绘一次
            Shot shot = myTank.getShot();
            g.setColor(Color.yellow);
            g.draw3DRect(shot.getX(),shot.getY(),1,1,false);
        }*/

        //循环画出自己坦克多发子弹的线路
        Vector<Shot> shots = myTank.getShots();
        for (int i = 0; i < shots.size(); i++) {
            Shot shot = shots.get(i);
            if(myTank.isLive() == true && shot != null && shot.isLive() == true){//如果子弹存活,画出射击轨迹
                g.setColor(Color.yellow);
                g.draw3DRect(shot.getX(),shot.getY(),1,1,false);
            }else{//从shots集合中移除
                shots.remove(shot);
            }
        }

        //画炸弹,如果bombs集合中有数据,就画出
        for (int i = 0; i < bombs.size(); i++) {
            //拿出炸弹
            Bomb bomb = bombs.get(i);
            //根据当前对象的life值,画出对应的图片
            if(bomb.getLife() > 6){
                g.drawImage(image1,bomb.getX(),bomb.getY(),60,60,this);
            }else if(bomb.getLife() > 3){
                g.drawImage(image2,bomb.getX(),bomb.getY(),60,60,this);
            }else {
                g.drawImage(image3,bomb.getX(),bomb.getY(),60,60,this);
            }
            //让炸弹的生命值减少
            bomb.lifeDown();
            //如果炸弹的生命值为0,从bombs集合中删除
            if(bomb.getLife() == 0){
                bombs.remove(bomb);
            }
        }

        //画敌人的坦克,遍历Vector
        for (int i = 0; i < enemyTanks.size(); i++) {
            //获取当前敌人坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            //如果敌人坦克还存活,
            if(enemyTank.isLive()){
                //画出敌人的坦克
                drawTank(enemyTank.getX(),enemyTank.getY(),g,enemyTank.getDirection(),0);
                //画出敌人坦克的所有子弹
                drawEnemyShots(enemyTank.getShots(),g);
            }
        }
    }

    /**
     * 3.画坦克的方法
     * @param x             坦克的左上角x坐标
     * @param y             坦克的左上角y坐标
     * @param g             画笔
     * @param direction     坦克的朝向(0上、1右、2下、3左)顺时针
     * @param type          坦克的类型：0敌人的坦克,1我的坦克
     */
    public void drawTank(int x,int y,Graphics g,int direction,int type){
        //根据坦克的类型,设置颜色
        switch (type){
            case 0://敌人的坦克
                g.setColor(Color.cyan);//设置颜色
                break;
            case 1://我的坦克
                g.setColor(Color.yellow);//设置颜色
                break;
        }

        //根据坦克的方向,绘制坦克(0上、1右、2下、3左)顺时针
        switch (direction){
                /*fill3DRect:画3D矩形、fillOval画圆形、drawLine画线*/
            case 0://上
                g.fill3DRect(x,y,10,60,false);//画坦克左边的轮子
                g.fill3DRect(x+30,y,10,60,false);//画坦克右边的轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画坦克中间的位置
                g.fillOval(x+10,y+20,20,20);//画坦克中间的盖子
                g.drawLine(x+20,y+30,x+20,y);//画坦克的炮筒
                break;
            case 1://右
                g.fill3DRect(x,y,60,10,false);//画坦克上边的轮子
                g.fill3DRect(x,y+30,60,10,false);//画坦克下边的轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画坦克中间的位置
                g.fillOval(x+20,y+10,20,20);//画坦克中间的盖子
                g.drawLine(x+30,y+20,x+60,y+20);//画坦克的炮筒
                break;
            case 2://下
                g.fill3DRect(x,y,10,60,false);//画坦克左边的轮子
                g.fill3DRect(x+30,y,10,60,false);//画坦克右边的轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画坦克中间的位置
                g.fillOval(x+10,y+20,20,20);//画坦克中间的盖子
                g.drawLine(x+20,y+30,x+20,y+60);//画坦克的炮筒
                break;
            case 3://左
                g.fill3DRect(x,y,60,10,false);//画坦克上边的轮子
                g.fill3DRect(x,y+30,60,10,false);//画坦克下边的轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画坦克中间的位置
                g.fillOval(x+20,y+10,20,20);//画坦克中间的盖子
                g.drawLine(x+30,y+20,x,y+20);//画坦克的炮筒
                break;
            default:
                System.out.println("未知方向。。。");
        }
    }

    /**
     * 4.画敌人坦克子弹的射击轨迹
     * @param shots         子弹线程
     * @param g             画笔
     */
    public void drawEnemyShots(Vector<Shot> shots,Graphics g){
        for (int j = 0; j < shots.size(); j++) {
            //取出子弹
            Shot shot = shots.get(j);
            //绘制子弹射击轨迹
            if(shot.isLive()){//ifLive == true
                g.setColor(Color.cyan);
                g.draw3DRect(shot.getX(),shot.getY(),1,1,false);
            }else{//从Vector中移除子弹
                shots.remove(shot);
            }
        }
    }

    /**
     * 5.启动MyPanel线程,调用start()方法时,
     * 每隔100毫秒,重绘一次,绘出子弹的发射轨迹...
     */
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            hitEnemyTank();//我的坦克是否击中敌人的坦克
            hitHeroTank();//敌人的坦克是否击中我的坦克
            this.repaint();//会触发paint()方法,重新绘图
        }
    }


    /**
     *
     * 6.判我的坦克子弹是否击中敌人的坦克,
     *    敌人的坦克子弹是否击中我的坦克,
     * @param shot
     * @param enemyTank
     */
    public void hitTank(Shot shot,Tank enemyTank){
        //根据敌人坦克的方向来判断
        switch (enemyTank.getDirection()){
            case 0://上
            case 2://下
                if(shot.getX() > enemyTank.getX() && shot.getX() < enemyTank.getX() + 40 &&
                        shot.getY() > enemyTank.getY() && shot.getY() < enemyTank.getY() + 60){
                    //子弹销毁
                    shot.setLive(false);
                    //敌人坦克销毁
                    enemyTank.setLive(false);
                    //从enemyTanks集合中移除被击中的坦克
                    enemyTanks.remove(enemyTank);
                    //创建Bomb对象,加入到bombs集合中
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
            case 1://右
            case 3://左
                if(shot.getX() > enemyTank.getX() && shot.getX() < enemyTank.getX() + 60 &&
                        shot.getY() > enemyTank.getY() && shot.getY() < enemyTank.getY() + 40){
                    //子弹销毁
                    shot.setLive(false);
                    //敌人坦克销毁
                    enemyTank.setLive(false);
                    //从enemyTanks集合中移除被击中的坦克
                    enemyTanks.remove(enemyTank);
                    //创建Bomb对象,加入到bombs集合中
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
        }
    }

    /**
     * 我的坦克是否击中敌人的坦克
     */
    public void hitEnemyTank(){
        /*Vector<Shot> shots = myTank.getShots();
        //遍历所有的子弹
        for (int j = 0; j < shots.size(); j++) {
            Shot shot = shots.get(j);
            //判断我的子弹是否存活
            if(shot != null && shot.isLive()){
                //遍历敌人的坦克
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    hitTank(shot,enemyTank);
                }
            }
        }*/

        //判断我的子弹是否存活,是否击中敌人的坦克
        Shot shot = myTank.getShot();
        if(shot != null && shot.isLive()){
            //遍历敌人的坦克
            for (int i = 0; i < enemyTanks.size(); i++) {
                EnemyTank enemyTank = enemyTanks.get(i);
                hitTank(shot,enemyTank);
            }
        }
    }

    /**
     * 敌人的坦克是否击中我的坦克
     */
    public void hitHeroTank(){
        //遍历敌人的坦克
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            //遍历敌人所有的子弹
            Vector<Shot> enemyTankShots = enemyTank.getShots();
            for (int j = 0; j < enemyTankShots.size(); j++) {
                Shot shot = enemyTankShots.get(j);
                if(myTank.isLive() && shot.isLive()){
                    hitTank(shot,myTank);
                }
            }
            
        }
    }

    /**
     * 7.当键盘上的某个键被按下时,触发
     * 按下键：W上、D右、S下、A左,让tank动起来
     * 按下J键：开启一个子弹线程,发射子弹
     * 需切换到英文输入法
     * @param e
     */
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        /*System.out.println((char)keyCode +"键被按下...");*/

        if(keyCode == KeyEvent.VK_W){//W上
            myTank.setDirection(0);
            if(myTank.getY() > 0){
                myTank.moveUp();
            }
        }else if(keyCode == KeyEvent.VK_D){//D右
            myTank.setDirection(1);
            if(myTank.getX()+60 < 1000){
                myTank.moveRight();
            }
        }else if(keyCode == KeyEvent.VK_S){//S下
            myTank.setDirection(2);
            if(myTank.getY()+60 < 750){
                myTank.moveDown();
            }
        }else if(keyCode == KeyEvent.VK_A){//A左
            myTank.setDirection(3);
            if(myTank.getX() > 0){
                myTank.moveLeft();
            }
        }else if(keyCode == KeyEvent.VK_J){//J键启动线程,发射子弹
            System.out.println("启动：射击敌人坦克线程...");
            //判断自己坦克的子弹是否销毁,只要没有销毁,就不能发射第二颗子弹：单发
            /*if(myTank.getShot() == null || !myTank.getShot().isLive()){
                myTank.shotEnemyTank();
            }*/
            //多发子弹,只要按了J键,就发射子弹
            if(myTank.isLive() == true){
                myTank.shotEnemyTank();
            }
        }

        //然后重绘一下
        this.repaint();//会触发paint()方法,重新绘图
    }

    //有字符输出是,该方法就会触发
    @Override
    public void keyTyped(KeyEvent e) {

    }

    //当按下的某个键松开时,触发
    @Override
    public void keyReleased(KeyEvent e) {

    }
}
